package blackstar.performance.transform;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import blackstar.performance.PerformanceConfigConstants;
import blackstar.performance.transform.matcher.AndListPointCutMatcher;
import blackstar.performance.transform.matcher.DefaultPointCutMatcher;
import blackstar.performance.transform.matcher.ExcludeExactPointCutMatcher;
import blackstar.performance.transform.matcher.ExcludeGetterPointCutMatcher;
import blackstar.performance.transform.matcher.ExcludeSetterPointCutMatcher;
import blackstar.performance.transform.matcher.OrListPointCutMatcher;
import blackstar.performance.transform.matcher.PointCutMatcher;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class PerformanceConfiger implements PerformanceConfigConstants
{
	private final static Logger LOGGER = Logger
			.getLogger(PerformanceConfiger.class.getSimpleName());

	public PointCutMatcher parsePointCutMatcher(Properties configs)
	{
		try
		{
			String id = configs.getProperty(ID_CONFIG);

			String configFileName = configs
					.getProperty(PERFORMANCE_CONFIG_PATH)
					+ File.separator + id + ".xml";

			if (configFileName != null)
			{
				File configFile = new File(configFileName);
				if (configFile.exists() && configFile.isFile())
				{
					DocumentBuilderFactory factory = DocumentBuilderFactory
							.newInstance();
					factory
							.setAttribute(
									"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
									"http://www.w3.org/2001/XMLSchema");

					DocumentBuilder docBuilder = null;
					InputStream source = null;
					try
					{
						source = new FileInputStream(configFile);
						docBuilder = factory.newDocumentBuilder();
						Document doc;
						doc = docBuilder.parse(new InputSource(source));
						Element root = doc.getDocumentElement();
						return parseMatcher(root);
					} finally
					{
						if (source != null)
						{
							source.close();
						}
					}
				} else
				{

					LOGGER.warning("performance config file[" + configFileName
							+ "] not found");
				}

			} else
			{
				LOGGER.warning("no performance config found for system[" + id
						+ "]");
			}
		} catch (Exception e)
		{
			LOGGER.warning("Error When Parse Weaving Config:" + e.getMessage());
		}
		return null;
	}

	private PointCutMatcher parseMatcher(Element root)
	{
		AndListPointCutMatcher matcher = new AndListPointCutMatcher();
		// setter
		String execludeSetter = root.getAttribute("excludeSetter");
		if (!"false".equals(execludeSetter))
		{
			matcher.addMethodMatcher(new ExcludeSetterPointCutMatcher());
		}

		// getter
		String excludeGetter = root.getAttribute("excludeGetter");
		if (!"false".equals(excludeGetter))
		{
			matcher.addMethodMatcher(new ExcludeGetterPointCutMatcher());
		}
		
		String excludeToString = root.getAttribute("excludeToString");
		if (!"false".equals(excludeToString))
		{
			matcher.addMethodMatcher(new ExcludeExactPointCutMatcher("toString()Ljava/lang/String;"));
		}
		
		String excludeEquals = root.getAttribute("excludeEquals");
		if (!"false".equals(excludeEquals))
		{
			matcher.addMethodMatcher(new ExcludeExactPointCutMatcher("equals(Ljava/lang/Object;)Z"));
		}
		
		String excludeHashcode = root.getAttribute("excludeHashcode");
		if (!"false".equals(excludeHashcode))
		{
			matcher.addMethodMatcher(new ExcludeExactPointCutMatcher("hashCode()I"));
		}

		OrListPointCutMatcher packageMethodMatchers = new OrListPointCutMatcher();
		NodeList nodeList = root.getElementsByTagName("package");
		for (int i = 0; i < nodeList.getLength(); i++)
		{
			PointCutMatcher methodMatcher = parseMethodMatcher((Element) nodeList
					.item(i));
			packageMethodMatchers.addMethodMatcher(methodMatcher);
			methodMatcher = null;
		}
		matcher.addMethodMatcher(packageMethodMatchers);

		return matcher;
	}

	private PointCutMatcher parseMethodMatcher(Element item)
	{
		DefaultPointCutMatcher defaultMatcher = new DefaultPointCutMatcher();
		defaultMatcher.addIncludePackage(item.getAttribute("name"));

		NodeList classNodeList = item.getElementsByTagName("class");
		for (int i = 0; i < classNodeList.getLength(); i++)
		{
			defaultMatcher.addIncludeClassRegExp(((Element) classNodeList
					.item(i)).getAttribute("regexp"));
		}

		NodeList methodNodeList = item.getElementsByTagName("method");
		for (int i = 0; i < methodNodeList.getLength(); i++)
		{
			defaultMatcher.addIncludeMethodRegExp(((Element) methodNodeList
					.item(i)).getAttribute("regexp"));
		}

		return defaultMatcher;
	}
}
